----------Micro-LADS Volume 3----------
--------------Prepositions-------------
A 4am crack                  2016-09-29
---------------------------------------

Name: Micro-LADS Volume 3: Prepositions
Genre: educational
Year: 1989
Credits:
  Bernard J. Fox
  Mary Sweig Wilson
Publisher: Laureate Learning Systems
Platform: Apple ][+ or later (64K)
Media: single-sided 5.25-inch floppy
OS: custom
Previous cracks: none
Identical cracks:
  #855 Micro-LADS Volume 2
  #854 Micro-LADS Volume 1
  #853 Following Directions Volume 2
  #852 Following Directions Volume 1
  #851 Early Emerging Rules: Plurals
  #850 Early Emerging Rules: Negation
  #849 Creature Magic
  #848 Concentrate on Words &
       Concepts II
  #847 Concentrate on Words & Concepts

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  immediate disk read error

Locksmith Fast Disk Backup
  unable to read any track

EDD 4 bit copy (no sync, no count)
  works

Copy ][+ nibble editor
  T00 -> modified epilogues
  T01+ -> automated analysis finds no
  structure, but I think I found it

                 --v--

   COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------

TRACK: 01  START: 1800  LENGTH: 3DFF

1BA8: DF DD B3 CD AE 9B B6 B7   VIEW
1BB0: 9F DE AC AF EF D3 96 CE
1BB8: 9D F7 D6 A6 F2 DA D7 FE
1BC0: EE AB F3 A7 97 F4 FF EC
1BC8: FF BF ED BB AF A5 CA 96
                     ^^^^^^^^
                 address prologue

1BD0: AE BF AA AB AF AA AB BE
      ^^^^^ ^^^^^ ^^^^^ ^^^^^
      V=$10 T=$01 S=$0A chksm

1BD8: FE FE FF B4 96 AE ED AA
      ^^^^^^^^
  address epilogue

1BE0: FF FB BF FD AE FE CA AD
                  ^^^^^^^^
               data prologue?

1BE8: 96 96 96 B4 C1 CD 96 96

---------------------------------------

  A  TO ANALYZE DATA  ESC TO QUIT

  ?  FOR HELP SCREEN  /  CHANGE PARMS

  Q  FOR NEXT TRACK   SPACE TO RE-READ

                 --^--

Disk Fixer
  ["O" -> "Input/Output Control"]
    set CHECKSUM ENABLED to "NO"
  T00 readable -> looks like a modified
    DOS 3.3-ish bootloader
  ["O" -> "Input/Output Control"]
    set Address Prologue to "A5 CA 96"
    set Data Epilogue to "AE FE CA"
  no luck, T01+ still unreadable
    (not sure why -- maybe a custom
    nibble translate table?)

Why didn't COPYA work?
  modified prologues & epilogues

Why didn't Locksmith FDB work?
  ditto

EDD worked. What does that tell us?
  no half or quarter tracks
  almost certainly no nibble check
  (just structural changes to prologues
  and epilogues)

The bootloader is just non-standard
enough that Passport can't trace it,
and the lack of any access to tracks
$01-$22 limits my avenues of attack.

Next steps:

  1. trace the boot to capture the RWTS
  2. convert disk to standard format
     with Advanced Demuffin
  3. patch RWTS to read standard format

                   ~

               Chapter 1
  In Which We Start At The Beginning


I have two floppy drives, one in slot 6
and the other in slot 5. My "work disk"
(in slot 5) runs Diversi-DOS 64K, which
is compatible with Apple DOS 3.3 but
relocates most of DOS to the language
card on boot. This frees up most of
main memory (only using a single page
at $BF00..$BFFF), which is useful for
loading large files or examining code
that lives in areas typically reserved
for DOS.

[S6,D1=original disk]
[S5,D1=my work disk]

The floppy drive firmware code at $C600
is responsible for aligning the drive
head and reading sector 0 of track 0
into main memory at $0800. Because the
drive can be connected to any slot, the
firmware code can't assume it's loaded
at $C600. If the floppy drive card were
removed from slot 6 and reinstalled in
slot 5, the firmware code would load at
$C500 instead.

To accommodate this, the firmware does
some fancy stack manipulation to detect
where it is in memory (which is a neat
trick, since the 6502 program counter
is not generally accessible). However,
due to space constraints, the detection
code only cares about the lower 4 bits
of the high byte of its own address.

$C600 (or $C500, or anywhere in $Cx00)
is read-only memory. I can't change it,
which means I can't stop it from
transferring control to the boot sector
of the disk once it's in memory. BUT!
The disk firmware code works unmodified
at any address. Any address that ends
with $x600 will boot slot 6, including
$B600, $A600, $9600, &c.

; copy drive firmware to $9600
*9600<C600.C6FFM

; and execute it
*9600G
...reboots slot 6, loads game...

Now then:

]PR#5
...
]CALL -151

*9600<C600.C6FFM

*96F8L

96F8-   4C 01 08    JMP   $0801

That's where the disk controller ROM
code ends and the on-disk code begins.
But $9600 is part of read/write memory.
I can change it at will. So I can
interrupt the boot process after the
drive firmware loads the boot sector
from the disk but before it transfers
control to the disk's bootloader.

; instead of jumping to on-disk code,
; copy boot sector to higher memory so
; it survives a reboot
96F8-   A0 00       LDY   #$00
96FA-   B9 00 08    LDA   $0800,Y
96FD-   99 00 28    STA   $2800,Y
9700-   C8          INY
9701-   D0 F7       BNE   $96FA

; turn off slot 6 drive motor
9703-   AD E8 C0    LDA   $C0E8

; reboot to my work disk in slot 5
9706-   4C 00 C5    JMP   $C500

*9600G
...reboots slot 6...
...reboots slot 5...

]BSAVE BOOT0,A$2800,L$100

Now we get to follow the boot process
one sector, one page, one instruction
at a time.

                   ~

               Chapter 2
           In Which We Loop


]CALL -151

*800<2800.28FFM

*801L

; this starts off looking like the
; normal DOS 3.3 bootloader
0801-   A5 27       LDA   $27
0803-   C9 09       CMP   #$09
0805-   D0 27       BNE   $082E
0807-   A5 2B       LDA   $2B
0809-   4A          LSR
080A-   4A          LSR
080B-   4A          LSR
080C-   4A          LSR
080D-   09 C0       ORA   #$C0
080F-   85 3F       STA   $3F
0811-   A9 5C       LDA   #$5C
0813-   85 3E       STA   $3E

; now we've gone right off the rails by
; enabling RAM bank 2
0815-   AD 83 C0    LDA   $C083
0818-   AD 83 C0    LDA   $C083

; testing for 64K
081B-   A9 A5       LDA   #$A5
081D-   8D 00 D0    STA   $D000
0820-   CD 00 D0    CMP   $D000
0823-   D0 63       BNE   $0888
0825-   4A          LSR
0826-   8D 00 D0    STA   $D000
0829-   CD 00 D0    CMP   $D000
082C-   D0 5A       BNE   $0888

; OK we have 64K -- continue the boot
; by checking the number of sectors
; left to load from track 0
082E-   AE FF 08    LDX   $08FF

; branch if done loading
0831-   30 1E       BMI   $0851

; if 2 sectors remain, reset the target
; address (this is very odd, I have
; literally never seen this before)
0833-   E0 02       CPX   #$02
0835-   D0 05       BNE   $083C
0837-   A9 BF       LDA   #$BF
0839-   8D FE 08    STA   $08FE

; this is the usual way to re-use the
; drive controller ROM to read sectors
; from track 0 (a bootstrap until we
; have enough code in memory to read
; the rest of the disk)
083C-   BD 78 08    LDA   $0878,X
083F-   85 3D       STA   $3D
0841-   CE FF 08    DEC   $08FF
0844-   AD FE 08    LDA   $08FE
0847-   85 27       STA   $27
0849-   CE FE 08    DEC   $08FE

; and jump to $Cx5C (set at $080F),
; which will read a sector and exit via
; $0801, so this entire thing is a loop
; that only exits when $08FF goes
; negative and the "BMI" instruction at
; $0831 branches to $0851
084C-   A6 2B       LDX   $2B
084E-   6C 3E 00    JMP   ($003E)

; execution continues here once all
; sectors are loaded
0851-   EE FE 08    INC   $08FE
0854-   EE FE 08    INC   $08FE

; back to ROM
0857-   8D 81 C0    STA   $C081
085A-   8D 81 C0    STA   $C081

; PR#0/IN#0/TEXT
085D-   20 89 FE    JSR   $FE89
0860-   20 93 FE    JSR   $FE93
0863-   20 2F FB    JSR   $FB2F

; set a presumably unfriendly reset
; vector
0866-   A9 A3       LDA   #$A3
0868-   8D F2 03    STA   $03F2
086B-   A9 08       LDA   #$08
086D-   8D F3 03    STA   $03F3
0870-   A9 AD       LDA   #$AD
0872-   8D F4 03    STA   $03F4

; jump to the next stage of the boot
0875-   6C FD 08    JMP   ($08FD)

Where are we storing these sectors in
memory?

*8FE.8FF

08FE- FF 0B

So we load 9 pages directly into RAM
bank 2 ($F700..$FFFF). Then, when X=2
(at $0833), we reset the target address
and load the final 2 sectors into
$BE00..$BFFF in main memory. Then we
exit the boot0 loop via the "BMI" to
$0851, and jump to ($08FD) -- which is
$BE00 by now -- to continue the boot.

Whew.

*9600<C600.C6FFM

; set up a callback in the boot sector
; to call our code instead of jumping
; to $BE00
96F8-   A9 4C       LDA   #$4C
96FA-   8D 75 08    STA   $0875
96FD-   A9 0A       LDA   #$0A
96FF-   8D 76 08    STA   $0876
9702-   A9 97       LDA   #$97
9704-   8D 77 08    STA   $0877

; start the boot
9707-   4C 01 08    JMP   $0801

; (callback is here)
; switch to RAM bank 2 and copy the
; code to main memory
970A-   AD 83 C0    LDA   $C083
970D-   AD 83 C0    LDA   $C083
9710-   A2 09       LDX   #$09
9712-   A0 00       LDY   #$00
9714-   B9 00 F7    LDA   $F700,Y
9717-   99 00 27    STA   $2700,Y
971A-   C8          INY
971B-   D0 F7       BNE   $9714
971D-   EE 16 97    INC   $9716
9720-   EE 19 97    INC   $9719
9723-   CA          DEX
9724-   D0 EE       BNE   $9714

; back to ROM
9726-   AD 82 C0    LDA   $C082

; also copy the 2 pages in main memory
9729-   B9 00 BE    LDA   $BE00,Y
972C-   99 00 3E    STA   $3E00,Y
972F-   B9 00 BF    LDA   $BF00,Y
9732-   99 00 3F    STA   $3F00,Y
9735-   C8          INY
9736-   D0 F1       BNE   $9729

; turn off slot 6 drive motor
9738-   AD E8 C0    LDA   $C0E8

; and reboot to my work disk
973B-   4C 00 C5    JMP   $C500

*BSAVE TRACE,A$9600,L$13E
*9600G
...reboots slot 6...
...reboots slot 5...

]BSAVE OBJ.F700-FFFF,A$2700,L$900
]BSAVE OBJ.BE00-BFFF,A$3E00,L$200

                   ~

               Chapter 3
       In Which We See The Light
       At The End Of The Tunnel,
       And It's A DOS-shaped RWTS
       Which Is A Weird Thing To
       See In A Tunnel, Honestly


]CALL -151

Finally, some good news. Check it out:

*2D00L

2D00-   84 48       STY   $48
2D02-   85 49       STA   $49
2D04-   A0 02       LDY   #$02
2D06-   8C F8 06    STY   $06F8
2D09-   A0 04       LDY   #$04
2D0B-   8C F8 04    STY   $04F8
2D0E-   A0 01       LDY   #$01
2D10-   B1 48       LDA   ($48),Y
2D12-   AA          TAX
2D13-   A0 0F       LDY   #$0F
2D15-   D1 48       CMP   ($48),Y
2D17-   F0 1B       BEQ   $2D34

That looks exactly like the standard
entry point of a DOS 3.3-shaped RWTS.
Of course it would be loaded at $FD00
instead of $BD00, but still.

Also this:

*294FL

; match address prologue ("A5 CA 96")
294F-   BD 8C C0    LDA   $C08C,X
2952-   10 FB       BPL   $294F
2954-   C9 A5       CMP   #$A5
2956-   D0 F0       BNE   $2948
2958-   EA          NOP
2959-   BD 8C C0    LDA   $C08C,X
295C-   10 FB       BPL   $2959
295E-   C9 CA       CMP   #$CA
2960-   D0 F2       BNE   $2954
2962-   A0 03       LDY   #$03
2964-   BD 8C C0    LDA   $C08C,X
2967-   10 FB       BPL   $2964
2969-   C9 96       CMP   #$96
296B-   D0 E7       BNE   $2954

And this:

*28E1L

; match data prologue ("FE CA AD")
28E1-   BD 8C C0    LDA   $C08C,X
28E4-   10 FB       BPL   $28E1
28E6-   49 FE       EOR   #$FE
28E8-   D0 F4       BNE   $28DE
28EA-   EA          NOP
28EB-   BD 8C C0    LDA   $C08C,X
28EE-   10 FB       BPL   $28EB
28F0-   C9 CA       CMP   #$CA
28F2-   D0 F2       BNE   $28E6
28F4-   A0 56       LDY   #$56
28F6-   BD 8C C0    LDA   $C08C,X
28F9-   10 FB       BPL   $28F6
28FB-   C9 AD       CMP   #$AD
28FD-   D0 E7       BNE   $28E6

Hey, that explains why I couldn't read
T01+ with a sector editor. I
misinterpreted the raw nibbles and
thought the data prologue started one
nibble earlier ("AE FE CA").

But wait, there's more custom stuff in
this RWTS, in exactly the relative
offsets I would expect from a DOS 3.3-
shaped RWTS. Here are the nibble
translate tables:

*2A29.2A68

2A29- .. 96 97 9A 9B 9D 9E 9F
2A30- A6 A7 AB AC AD AE AF B2
2A38- B3 B4 B5 B6 B7 B9 BA BB
2A40- BC BD BE BF CB CD CE CF
2A48- D3 D5 D7 D9 DA DB DC DD
         ^^

2A50- DE DF E5 E6 E7 E9 EA EB
2A58- EC ED EE EF F2 F3 F4 F5
2A60- F6 F7 F9 FA FB FC FD FE
2A68- FF

*2A96.2AFF

2A96- .. .. .. .. .. .. 00 01
2A98- 98 99 02 03 9C 04 05 06
2AA0- A0 A1 A2 A3 A4 A5 07 08
2AA8- A8 A9 AA 09 0A 0B 0C 0D
2AB0- B0 B1 0E 0F 10 11 12 13
2AB8- B8 14 15 16 17 18 19 1A
2AC0- C0 C1 C2 C3 C4 C5 C6 C7
2AC8- C8 C9 CA 1B CC 1C 1D 1E
2AD0- D0 D1 D2 1F D4 20 D6 21
                  ^^ ^^

2AD8- D8 22 23 24 25 26 27 28
2AE0- E0 E1 E2 E3 E4 29 2A 2B
2AE8- E8 2C 2D 2E 2F 30 31 32
2AF0- F0 F1 33 34 35 36 37 38
2AF8- F8 39 3A 3B 3C 3D 3E 3F

I marked the three differences from the
standard nibble translate tables.

With the knowledge that this RWTS works
just like a DOS 3.3 RWTS (except it
lives in RAM bank 2 at $F800), we can
begin the process of converting the
disk to a standard format.

                   ~

               Chapter 4
   In Which We Use The Original Disk
      As A Weapon Against Itself


*BLOAD ADVANCED DEMUFFIN 1.5

Since this RWTS does not have the usual
entry point (at $BD00), I get to write
an IOB module to tell Advanced Demuffin
how to call the custom RWTS. (Read the
Advanced Demuffin docs on my work disk
for more on IOB modules.)

; standard Advanced Demuffin setup
; (unchanged)
1400-   4A          LSR
1401-   8D 22 0F    STA   $0F22
1404-   8C 23 0F    STY   $0F23
1407-   8E 27 0F    STX   $0F27
140A-   A9 01       LDA   #$01
140C-   8D 20 0F    STA   $0F20
140F-   8D 2A 0F    STA   $0F2A

; switch to RAM bank 2
1412-   AD 83 C0    LDA   $C083
1415-   AD 83 C0    LDA   $C083

; call RWTS
1418-   A9 0F       LDA   #$0F
141A-   A0 1E       LDY   #$1E
141C-   20 00 FD    JSR   $FD00

; switch back to ROM (because Advanced
; Demuffin uses ROM routines like $FDF0
; for printing)
141F-   AD 82 C0    LDA   $C082

; return to Advanced Demuffin
1422-   60          RTS

*BSAVE IOB,A$1400,L$FB

Now I get to make a small program to
move the RWTS into place. There's
probably an easy way to do this solely
on the monitor command line, but I
crashed my computer twice trying to
figure out what it was, so meh.

; switch to RAM bank
0300-   AD 83 C0    LDA   $C083
0303-   AD 83 C0    LDA   $C083

; copy RWTS $2800 -> $F800
0306-   A2 08       LDX   #$08
0308-   A0 00       LDY   #$00
030A-   B9 00 28    LDA   $2800,Y
030D-   99 00 F8    STA   $F800,Y
0310-   C8          INY
0311-   D0 F7       BNE   $030A
0313-   EE 0C 03    INC   $030C
0316-   EE 0F 03    INC   $030F

; 8 pages worth
0319-   CA          DEX
031A-   D0 EE       BNE   $030A

; switch back to ROM
031C-   AD 82 C0    LDA   $C082
031F-   60          RTS

*BSAVE RWTS MOVER,A$300,L$20

; disconnect DOS
*FE89G FE93G

; move RWTS to RAM bank
*300G

; start Advanced Demuffin
*800G

From my inspection with a nibble editor
and sector editor, I know that track 0
is (mostly) standard. This RWTS is only
for tracks $01-$22. Advanced Demuffin
can handle that.

["C" to convert disk]

["Y" to change default values]

                 --v--

ADVANCED DEMUFFIN 1.5    (C) 1983, 2014
ORIGINAL BY THE STACK    UPDATES BY 4AM
=======================================


INPUT ALL VALUES IN HEX


SECTORS PER TRACK? (13/16) 16

START TRACK: $01        <-- change this
START SECTOR: $00       <-- change this
END TRACK: $22
END SECTOR: $0F

INCREMENT: 1

MAX # OF RETRIES: 0

COPY FROM DRIVE 1
TO DRIVE: 2
=======================================
16SC $01,$00-$22,$0F BY1.0 S6,D1->S6,D2

                 --^--

After putting a blank disk in S6,D2,
it's time for the big finale:

                 --v--

ADVANCED DEMUFFIN 1.5    (C) 1983, 2014
ORIGINAL BY THE STACK    UPDATES BY 4AM
=======PRESS ANY KEY TO CONTINUE=======
TRK: ..................................
+.5:
    0123456789ABCDEF0123456789ABCDEF012
SC0: ..................................
SC1: ..................................
SC2: ..................................
SC3: ..................................
SC4: ..................................
SC5: ..................................
SC6: ..................................
SC7: ..................................
SC8: ..................................
SC9: ..................................
SCA: ..................................
SCB: ..................................
SCC: ..................................
SCD: ..................................
SCE: ..................................
SCF: ..................................
=======================================
16SC $01,$00-$22,$0F BY1.0 S6,D1->S6,D2

                 --^--

This is the power and the genius of
Advanced Demuffin. Every disk must be
able to read itself. So, let it read
itself, then capture the data and write
it out in a standard format.

I also copied track 0 by loading up my
trusty Disk Fixer sector editor and
manually copying each sector from the
original disk to this demuffin'd copy.
Now I have all tracks converted.

Of course, this copy doesn't boot yet,
because it still has the original RWTS.
And since the RWTS code on track $00 is
shifted by two sectors, none of my
tools can detect or automatically patch
anything. I made these changes by hand
like some kind of 20th century teen.

; RWTS (prologues and epilogues)
T00,S04,$53: FE -> D5
T00,S04,$58: CA -> AA
T00,S04,$9E: FE -> DE
T00,S04,$A3: FE -> AA
T00,S04,$E7: FE -> D5
T00,S04,$F1: CA -> AA
T00,S05,$35: FE -> DE
T00,S05,$3F: FE -> AA
T00,S05,$55: A5 -> D5
T00,S05,$5F: CA -> AA
T00,S05,$91: FE -> DE
T00,S05,$9B: FE -> AA

; nibble translate tables
T00,S06,$49: D5 -> D6
T00,S06,$D5: 20 -> D5
T00,S06,$D6: D6 -> 20

; ignore non-standard disk volume #
T00,S0A,$12: B148 -> A900

]PR#6
...works...

Quod erat liberandum.

---------------------------------------
A 4am crack                     No. 856
------------------EOF------------------
